/**
 * Copyright 2012 Roger Cockshutt
 * krakenbrau@gmail.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.parallelrl.process;

import java.util.HashMap;
import java.util.List;
import java.util.Vector;

import com.googlecode.parallelrl.Config;
import com.googlecode.parallelrl.ParallelRL;
import com.googlecode.parallelrl.data.ecs.ECSManager;
import com.googlecode.parallelrl.display.Colors;
import com.googlecode.parallelrl.display.Screen;
import com.googlecode.parallelrl.util.Names;
import com.googlecode.parallelrl.util.Point2D;

/**
 * @author Roger Cockshutt
 *
 */
public class Behaviours {
	
	public static List<HashMap<String, String>> playercontrolled(Long me) {
		List<HashMap<String, String>> events = new Vector<>();
		String action = null;
		while (action == null
				|| BehaviourManager.ControlAction.names().contains(action)) {
			
			action = Config.keyMap.get(Screen.get().getch());

			if (BehaviourManager.ControlAction.names().contains(action)) {
				BehaviourManager.ControlAction.valueOf(action).process();
				if (!Game.running) {
					return events;
				}
				
				action = null;
			}
			if (ParallelRL.realTime && action == null) {
				action = "REST";
			}
		}
		
		Point2D moveDirection = null;
		Point2D strikeTarget = null;
		switch (action) {
		case "MOVE_UP":
			moveDirection = Point2D.up;
			break;
		case "MOVE_UP_LEFT":
			moveDirection = Point2D.up.sum(Point2D.left);
			break;
		case "MOVE_UP_RIGHT":
			moveDirection = Point2D.up.sum(Point2D.right);
			break;
		case "MOVE_DOWN":
			moveDirection = Point2D.down;
			break;
		case "MOVE_DOWN_LEFT":
			moveDirection = Point2D.down.sum(Point2D.left);
			break;
		case "MOVE_DOWN_RIGHT":
			moveDirection = Point2D.down.sum(Point2D.right);
			break;
		case "MOVE_LEFT":
			moveDirection = Point2D.left;
			break;
		case "MOVE_RIGHT":
			moveDirection = Point2D.right;
			break;
		case "STRIKE":
			Screen.get().rhetoricalPrompt("Strike where?", Colors.libTCOD.white.normal);
			strikeTarget = BehaviourManager.getUserSelectedSquare(1);
			break;
		case "REST":
			HashMap<String, String> rest = new HashMap<>();
			rest.put("time", String.valueOf(Game.currentStep + 100));
			rest.put("action", "turn");
			rest.put("entity", me.toString());
			events.add(rest);
			break;
		case "PICKUP":
			HashMap<String, String> pickup = new HashMap<>();
			pickup.put("time", String.valueOf(Game.currentStep));
			pickup.put("action", "pickup");
			pickup.put("entity", me.toString());
			events.add(pickup);
			break;
		default:
			break;
		}
		
		if (moveDirection != null) {
			Point2D myPos = ECSManager.getComponent(me, Names.position).coordinateValue();
			Point2D moveTarget = myPos.sum(moveDirection);
			List<Long> entitiesAtTarget = ECSTools.getAllWithin(moveTarget, 0, false);
			List<Long> entitiesWithBehaviour = ECSTools.selectForComponent(entitiesAtTarget, Names.behaviour);
			if (entitiesAtTarget.isEmpty() || entitiesWithBehaviour.isEmpty()) {
				HashMap<String, String> move = new HashMap<>();
				move.put("time", String.valueOf(Game.currentStep));
				move.put("action", "move");
				move.put("entity", me.toString());
				move.put("parameters", moveTarget.toString());
				events.add(move);
			} else {
				strikeTarget = moveTarget;
			}
		}
		if (strikeTarget != null) {
			HashMap<String, String> strike = new HashMap<>();
			strike.put("time", String.valueOf(Game.currentStep));
			strike.put("action", "strike");
			strike.put("entity", me.toString());
			strike.put("parameters", strikeTarget.toString());
			events.add(strike);
		}
		return events;
	}
	
	@SuppressWarnings("unused")
	public static List<HashMap<String, String>> none(Long me) {
		return new Vector<HashMap<String, String>>();
	}
	
	public static List<HashMap<String, String>> basic(Long me) {
		List<HashMap<String, String>> events = new Vector<>();
		
		// Search for adjacent enemies.
		Point2D myPos = ECSManager.getComponent(me, Names.position).coordinateValue();
		List<Long> nearbyEntities = ECSTools.getAllWithin(myPos, 1, true);
		String myAlignment = ECSManager.getComponentValue(me, Names.alignment);
		List<Long> adjacentEnemies = ECSTools.selectAgainstComponentValue(
				nearbyEntities, Names.alignment, myAlignment, true);
		// Are there any?
		if (!adjacentEnemies.isEmpty()) {
				// Strike one.
			Long target = adjacentEnemies.get(0);
				String targetPosition = ECSManager.getComponentValue(target, Names.position);
				HashMap<String, String> strike = new HashMap<>();
				strike.put("time", String.valueOf(Game.currentStep));
				strike.put("action", "strike");
				strike.put("entity", me.toString());
				strike.put("parameters", targetPosition);
				events.add(strike);
		} else {
			Point2D moveTarget = new Point2D(myPos.y, myPos.x);
			// Search for nearby enemies.
			nearbyEntities = ECSTools.getAllWithin(myPos, 7, true);
			// Are there any?
			List<Long> nearbyEnemies = ECSTools.selectAgainstComponentValue(
					nearbyEntities, Names.alignment, myAlignment, true);
			if (!nearbyEnemies.isEmpty()) {
				Long target = ECSTools.getNearestTo(myPos, nearbyEnemies, true);
				Point2D targetPos = ECSManager.getComponent(target, Names.position).coordinateValue();
				if (targetPos.y > myPos.y) {
					moveTarget = moveTarget.sum(Point2D.down);
				} else if (targetPos.y < myPos.y) {
					moveTarget = moveTarget.sum(Point2D.up);
				} else if (targetPos.y == myPos.y) {
					moveTarget = moveTarget.sum(Point2D.zero);
				}
				if (targetPos.x > myPos.x) {
					moveTarget = moveTarget.sum(Point2D.right);
				} else if (targetPos.x < myPos.x) {
					moveTarget = moveTarget.sum(Point2D.left);
				} else if (targetPos.x == myPos.x) {
					moveTarget = moveTarget.sum(Point2D.zero);
				}
			} else {
				// No nearby enemies; move randomly.
				moveTarget = moveTarget.sum(Point2D.randomDirection());
			}
			HashMap<String, String> move = new HashMap<>();
			move.put("time", String.valueOf(Game.currentStep));
			move.put("action", "move");
			move.put("entity", me.toString());
			move.put("parameters", moveTarget.toString());
			events.add(move);
		}
		
		return events;
	}

}
